package com.estate.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.estate.system.domain.CustomGeocodingResult;
import com.estate.system.domain.Listing;
import com.estate.system.domain.SuburbGeocoding;
import com.estate.system.mapper.SuburbGeocodingMapper;
import com.estate.system.service.GoogleGeocodingService;
import com.google.maps.GeoApiContext;
import com.google.maps.GeocodingApi;
import com.google.maps.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class GoogleGeocodingServiceImpl implements GoogleGeocodingService {
    
    @Value("${google.maps.api.key}")
    private String apiKey;
    
    @Autowired
    private SuburbGeocodingMapper suburbGeocodingMapper;

    @Override
    public CustomGeocodingResult geocodeSuburb(String suburb, String state, String countryCode) {
        try {
            // 创建 GeoApiContext（建议作为单例，不要每次创建）
            GeoApiContext context = new GeoApiContext.Builder()
                    .apiKey(apiKey)
                    .build();

            String address = String.format("%s, %s, Australia", suburb, state);

            // 使用新的 GeocodingApi
            GeocodingResult[] results = GeocodingApi.geocode(context, address)
                    .region("au")
                    .await();

            return parseGeocodingResponse(results);
        } catch (Exception e) {
            log.error("地理编码API调用失败: {}", e.getMessage());
            throw new RuntimeException("地理编码服务暂时不可用");
        }
    }

    private CustomGeocodingResult parseGeocodingResponse(GeocodingResult[] results) {
        if (results == null || results.length == 0) {
            throw new RuntimeException("未找到相关的地理编码结果");
        }

        GeocodingResult firstResult = results[0];
        Geometry geometry = firstResult.geometry;
        LatLng location = geometry.location;

        CustomGeocodingResult result = new CustomGeocodingResult();
        result.setLatitude(BigDecimal.valueOf(location.lat));
        result.setLongitude(BigDecimal.valueOf(location.lng));
        result.setFormattedAddress(firstResult.formattedAddress);
        result.setPlaceId(firstResult.placeId);

        // 解析地址组件
        parseAddressComponents(firstResult.addressComponents, result);

        return result;
    }

    private void parseAddressComponents(AddressComponent[] addressComponents, CustomGeocodingResult result) {
        if (addressComponents == null) return;

        for (AddressComponent component : addressComponents) {
            AddressComponentType[] types = component.types;

            if (containsType(types, AddressComponentType.COUNTRY)) {
                result.setCountryCode(component.shortName);
            } else if (containsType(types, AddressComponentType.ADMINISTRATIVE_AREA_LEVEL_1)) {
                result.setAdministrativeArea(component.longName);
            } else if (containsType(types, AddressComponentType.LOCALITY)) {
                result.setLocality(component.longName);
            } else if (containsType(types, AddressComponentType.POSTAL_CODE)) {
                result.setPostalCode(component.longName);
            }
        }
    }

    private boolean containsType(AddressComponentType[] types, AddressComponentType targetType) {
        if (types == null) return false;

        for (AddressComponentType type : types) {
            if (type == targetType) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<SuburbGeocoding> batchGeocodeListings(List<Listing> listings) {
        List<SuburbGeocoding> results = new ArrayList<>();

        // 创建单例的 GeoApiContext（推荐在类初始化时创建）
        GeoApiContext context = new GeoApiContext.Builder()
                .apiKey(apiKey)
                .build();

        for (Listing listing : listings) {
            try {
                // 解析JSON地址信息
                JSONObject addrJson = JSON.parseObject(listing.getListingAddr());
                String suburb = addrJson.getString("suburb");
                String state = addrJson.getString("state");

                // 检查是否已存在该行政区的地理编码
                SuburbGeocoding existing = suburbGeocodingMapper.selectBySuburb(suburb);
                if (existing != null) {
                    results.add(existing);
                    continue;
                }

                // 调用新的谷歌地图API
                String address = String.format("%s, %s, Australia", suburb, state);
                GeocodingResult[] geocodingResults = GeocodingApi.geocode(context, address)
                        .region("au")
                        .await();

                if (geocodingResults.length == 0) {
                    log.warn("未找到地址的地理编码结果: {}", address);
                    continue;
                }

                GeocodingResult geocodingResult = geocodingResults[0];
                Geometry geometry = geocodingResult.geometry;
                LatLng location = geometry.location;

                // 构建入库对象
                SuburbGeocoding geocoding = new SuburbGeocoding();
                geocoding.setListingId(Long.parseLong(listing.getListingId().toString()));
                geocoding.setSuburb(suburb);
                geocoding.setLatitude(BigDecimal.valueOf(location.lat));
                geocoding.setLongitude(BigDecimal.valueOf(location.lng));
                geocoding.setFormattedAddress(geocodingResult.formattedAddress);
                geocoding.setPlaceId(geocodingResult.placeId);

                // 解析地址组件
                parseAddressComponentsToSuburbGeocoding(geocodingResult.addressComponents, geocoding);

                saveGeocodingResult(geocoding);
                results.add(geocoding);

                // 添加延迟避免API限制
                Thread.sleep(100);

            } catch (Exception e) {
                log.error("处理房源 {} 的地理编码失败: {}", listing.getListingId(), e.getMessage());
            }
        }

        return results;
    }

    private void parseAddressComponentsToSuburbGeocoding(AddressComponent[] addressComponents, SuburbGeocoding geocoding) {
        if (addressComponents == null) return;

        for (AddressComponent component : addressComponents) {
            AddressComponentType[] types = component.types;

            if (containsType(types, AddressComponentType.COUNTRY)) {
                geocoding.setCountryCode(component.shortName);
            } else if (containsType(types, AddressComponentType.ADMINISTRATIVE_AREA_LEVEL_1)) {
                geocoding.setAdministrativeArea(component.longName);
            } else if (containsType(types, AddressComponentType.LOCALITY)) {
                geocoding.setLocality(component.longName);
            } else if (containsType(types, AddressComponentType.POSTAL_CODE)) {
                geocoding.setPostalCode(component.longName);
            }
        }
    }

    @Override
    public void saveGeocodingResult(SuburbGeocoding geocoding) {
        suburbGeocodingMapper.insert(geocoding);
    }
}